package com.yvtian.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.yvtian.admin.dao.SysUserDao;
import com.yvtian.admin.pojo.*;
import com.yvtian.admin.service.PermissionService;
import com.yvtian.admin.service.SysDeptService;
import com.yvtian.admin.service.SysRoleMenuService;
import com.yvtian.admin.service.SysUserService;
import com.yvtian.admin.vo.Permission;
import com.yvtian.admin.vo.RoleVO;
import com.yvtian.admin.vo.UserInfoResponse;
import com.yvtian.admin.vo.UserVO;
import com.yvtian.constants.TokenConstants;
import com.yvtian.constants.UserConstant;
import com.yvtian.entity.JWTInfo;
import com.yvtian.entity.Result;
import com.yvtian.entity.StatusCode;
import com.yvtian.exception.ParamsException;
import com.yvtian.exception.RecordException;
import com.yvtian.exception.UserInvalidException;
import com.yvtian.exception.UserRegisteredException;
import com.yvtian.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户(SysUser)表服务实现类
 *
 * @author long
 */
@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao,SysUser> implements SysUserService {
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private PermissionService permissionService;
    @Resource
    private SysDeptService sysDeptService;
    @Resource
    private SysRoleMenuService sysRoleMenuService;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    private final Gson gson = new Gson();

    @Override
    public UserInfoResponse findCurrentUserById(String userId) {
        UserInfoResponse userInfo = null;
        SysUser sysUser = sysUserDao.selectById(userId);
        if (null != sysUser) {
            userInfo = getUserInfoResponse(sysUser);
            writeUserInfo(userInfo);
        }
        return userInfo;
    }

    @Override
    public UserInfoResponse findUserById(String userId) {
        UserInfoResponse userInfo = null;
        SysUser tbUser = sysUserDao.selectById(userId);
        if (null != tbUser) {
            userInfo = getUserInfoResponse(tbUser);
        }
        return userInfo;
    }

    @Transactional
    @Override
    public void register(SysUser user) throws UserRegisteredException {
        Map<String, Object> map = new HashMap<>();
        map.put("account", user.getAccount());
        List<SysUser> userList = sysUserDao.selectByMap(map);
        if (userList.size() != 0) {
            throw new UserRegisteredException();
        }
        user.setId(String.valueOf(idWorker.nextId()));
        Date date = new Date();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String password = encoder.encode(user.getPassword());
        user.setPassword(password);
        user.setOnline(0L);
        user.setRegdate(date);
        user.setUpdatedate(date);
        user.setLastdate(date);
        sysUserDao.insert(user);

        //分配基础权限
//        sysRoleMenuService.save()
    }

    @Override
    public Map<String, Object> login(Map<String, String> map) throws UserInvalidException {
        String username = map.get("username");
        String password = map.get("password");
        SysUser tbUser = sysUserDao.selectByAccess(username);
        if (tbUser == null) {
            throw new UserInvalidException("用户名不存在或已注销!");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (encoder.matches(password, tbUser.getPassword())) {
            return getJWTInfo(tbUser);
        }
        throw new UserInvalidException("密码错误!");
    }

    @Override
    public void logout(String tokenId) {
        redisTemplate.delete(RedisConstant.REDIS_USER_TOKEN_KEY + ":" + tokenId);
        redisTemplate.delete(RedisConstant.REDIS_USER_INFO_KEY + ":" + tokenId);
    }

    @Override
    public IPage findByPage(Page<SysUser> sysUserPage, SysUser sysUser) {

//        LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        sysUserLambdaQueryWrapper.eq(SysUser::getIsDelete,0);

//        if (!StringHelper.isEmpty(sysUser.getRegDateStr())) {
//            String[] split = sysUser.getRegDateStr().split("~");
//            sysUserLambdaQueryWrapper.between(SysUser::getRegdate, DateUtils.parse(DateUtils.FormatType.type1, split[0])
//                    , DateUtils.parse(DateUtils.FormatType.type1, split[1]));
//        }
//        if (!StringHelper.isEmpty(sysUser.getNickname())){
//            sysUserLambdaQueryWrapper.like(SysUser::getNickname,sysUser.getNickname());
//        }
//        if (!StringHelper.isEmpty(sysUser.getAccount())){
//            sysUserLambdaQueryWrapper.like(SysUser::getAccount,sysUser.getAccount());
//        }
//        if (!StringHelper.isEmpty(sysUser.getEmail())){
//            sysUserLambdaQueryWrapper.like(SysUser::getEmail,sysUser.getEmail());
//        }
//        if (!StringHelper.isEmpty(sysUser.getSex())){
//            sysUserLambdaQueryWrapper.eq(SysUser::getSex,sysUser.getSex());
//        }
//        if (!StringHelper.isEmpty(sysUser.getMobile())){
//            sysUserLambdaQueryWrapper.like(SysUser::getMobile,sysUser.getMobile());
//        }
        ArrayList<SysDept> sysDepts = new ArrayList<>();
        if (sysUser.getDeptId() != null){
            sysDepts = sysDeptService.recursionDept(sysUser.getDeptId());
        }
        List<Integer> deptIds = sysDepts.stream()
                .map(SysDept::getDeptId)
                .collect(Collectors.toList());
        return sysUserDao.findUserByPage(sysUserPage,sysUser,deptIds);
    }

    @Override
    public List<UserInfoResponse> findList(String ids) {
        String[] split = ids.split(",");
        List<SysUser> tbUsers = sysUserDao.selectBatchIds(Arrays.asList(split));
        List<UserInfoResponse> users = new ArrayList<>();
        BeanUtils.copyProperties(tbUsers, users);
        return users;
    }

    /**
     * 更新用户的信息
     */
    @Override
    public void updateUser(SysUser tbUser) {
        tbUser.setUpdatedate(new Date());
        //更新实体类里面不为null的列
        sysUserDao.updateById(tbUser);
    }

    @Override
    public Result delUser(Map<String, Object> ids) {
        if (ObjectUtils.isNull(ids)) {
            throw new ParamsException("id不能为空");
        }

        if (ids.get("ids") instanceof String) {
            String userIds = (String) ids.get("ids");
            sysUserDao.delUsers(userIds);
        }else if (ids.get("ids") instanceof ArrayList){
            ArrayList<String> arrayList = (ArrayList<String>) ids.get("ids");
            LambdaUpdateWrapper<SysUser> sysUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            sysUserLambdaUpdateWrapper.set(SysUser::getIsDelete,1);
            sysUserLambdaUpdateWrapper.in(SysUser::getId,arrayList);
            this.update(sysUserLambdaUpdateWrapper);
        }else {
            return new Result(false, "删除失败，格式异常", StatusCode.OK);
        }
        return new Result(true, "删除成功", StatusCode.OK);
    }

    @Override
    public Result delUserById(String userId) {
        LambdaUpdateWrapper<SysUser> sysUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        sysUserLambdaUpdateWrapper.eq(SysUser::getId,userId);

        this.update(sysUserLambdaUpdateWrapper);
        return new Result(true, "删除成功", StatusCode.OK);
    }

    @Override
    public void restPassword(String id) {
//        TbUser user = tbUserDao.selectById(id);
        //加密同一个字符串会返回不同的值，但是matches()方法返回的还是true
        String encode = passwordEncoder.encode(UserConstant.USER_PASSWORD);
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("password", encode);
        sysUserDao.update(null, updateWrapper);
    }

    @Override
    public Result updatePassword(String userId, String oldPwd, String newPwd) {
        SysUser tbUser = sysUserDao.selectById(userId);
        if (passwordEncoder.matches(oldPwd, tbUser.getPassword())) {
            UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("password", passwordEncoder.encode(newPwd));
            updateWrapper.eq("id", userId);
            sysUserDao.update(null, updateWrapper);
            return new Result(true, "更新成功", StatusCode.OK);
        } else {
            return new Result(false, "密码错误", StatusCode.PASSWORD_ERROR);
        }
    }

    private Map<String, Object> getJWTInfo(SysUser tbUser) {
        JWTInfo jwtInfo = new JWTInfo();
        BeanUtils.copyProperties(tbUser, jwtInfo);
        String token = JwtTokenUtil.generateToken(jwtInfo, TokenConstants.SECRET_KEY);
        updateUserLoginInfo(tbUser);
        UserInfoResponse responseUser = getUserInfoResponse(tbUser);
        HashMap<String, Object> result = new HashMap<>();
        result.put("accessToken", token);
        result.put("tokenId", jwtInfo.getId());
        writeOnlineLog(jwtInfo, responseUser);
        return result;
    }

    /**
     * 更新用户登录信息
     */
    private void updateUserLoginInfo(SysUser tbUser) {
        Date date = new Date();
        tbUser.setLastdate(date);
        sysUserDao.updateById(tbUser);
    }

    /**
     * 封装返回的数据
     *
     * @param tbUser
     * @return
     */
    private UserInfoResponse getUserInfoResponse(SysUser tbUser) {
        List<TbPermission> tbPermissions = permissionService.getPermissionsByUserId(tbUser.getId());
        ArrayList<SysRole> tbRoles = sysUserDao.findRoleByUserId(tbUser.getId());
        List<RoleVO> roleVOS = new ArrayList<>();
        List<Permission> permissions = new ArrayList<>();
        UserInfoResponse responseUser = new UserInfoResponse();
        for (TbPermission tbPermission : tbPermissions) {
            Permission permission = new Permission();
            BeanUtils.copyProperties(tbPermission, permission);
            permissions.add(permission);
        }
        for (SysRole tbRole : tbRoles) {
            RoleVO roleVO = new RoleVO();
            BeanUtils.copyProperties(tbRole, roleVO);
            roleVOS.add(roleVO);
        }
        BeanUtils.copyProperties(tbUser, responseUser);
        responseUser.setPermissions(permissions);
        responseUser.setRoleVOS(roleVOS);
        return responseUser;
    }

    /**
     * 把Token信息和用户信息存入Redis
     *
     * @param jwtInfo Token的信息
     */
    public void writeOnlineLog(JWTInfo jwtInfo, UserInfoResponse userInfo) {
        redisTemplate.opsForValue().set(RedisConstant.REDIS_USER_TOKEN_KEY + ":" + jwtInfo.getId(), gson.toJson(jwtInfo, JWTInfo.class), RedisConstant.REDIS_USER_TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);
        writeUserInfo(userInfo);
    }


    public void writeUserInfo(UserInfoResponse userInfo) {
        redisTemplate.opsForValue().set(RedisConstant.REDIS_USER_INFO_KEY + ":" + userInfo.getId(), gson.toJson(userInfo, UserInfoResponse.class), RedisConstant.REDIS_USER_TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);
    }

//    @Override
//    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//        if (null == s | "".equals(s)){
//            /*
//                对被AbstractUserDetailsAuthenticationProvider类转成BadCredentialsException();
//                所以直接替换掉
//            */
//            throw new UsernameNotFoundException("用户名不能为空");
//        }
//        TbUser user = tbUserDao.selectByAccess(s);
//        System.out.println("user====="+user.toString());
//        JWTInfo jwtInfo = new JWTInfo();
//        BeanUtils.copyProperties(user, jwtInfo);
//        String token = JwtTokenUtil.generateToken(jwtInfo, secretKey);
//
//        writeOnlineLog(jwtInfo);
//        ArrayList<GrantedAuthority> list = new ArrayList<>();
//        List<TbRole> tbRoles = roleDao.selectRoleByUserId(user.getId());
//        for (TbRole tbRole : tbRoles) {
//            list.add(new SimpleGrantedAuthority(tbRole.getName()));
//        }
//        return new User(s, user.getPassword(), list);
//    }


}
